﻿using System;
using System.Collections.Generic;
using System.Text;

namespace RaisingStudio.Data.Expressions
{
    [Serializable]
    public class RelationExpression : ExpressionElement
    {
        private RelationOperator relationOperator;
        public RelationOperator RelationOperator
        {
            get
            {
                return this.relationOperator;
            }
            set
            {
                this.relationOperator = value;
            }
        }

        private ExpressionElement expressionElement;
        public ExpressionElement ExpressionElement
        {
            get
            {
                return this.expressionElement;
            }
            set
            {
                this.expressionElement = value;
            }
        }

        private List<RelationExpression> children;
        public List<RelationExpression> Children
        {
            get
            {
                if (this.children == null)
                {
                    this.children = new List<RelationExpression>();
                }
                return this.children;
            }
        }

        public bool HasChildren
        {
            get
            {
                return ((this.children != null) && (this.children.Count > 0));
            }
        }

        #region Constructor
        public RelationExpression()
        {
        }

        public RelationExpression(ExpressionElement expressionElement) 
            : this()
        {
            this.expressionElement = expressionElement;
        }

        public RelationExpression(RelationOperator relationOperator, ExpressionElement expressionElement)
            : this()
        {
            this.relationOperator = relationOperator;
            this.expressionElement = expressionElement;
        }

        public RelationExpression(OperationExpression operationExpression1, RelationOperator relationOperator, OperationExpression operationExpression2)
            : this()
        {
            RelationExpression relationExpression1 = new RelationExpression(operationExpression1);
            this.Children.Add(relationExpression1);
            RelationExpression relationExpression2 = new RelationExpression(operationExpression2);
            relationExpression2.RelationOperator = relationOperator;
            this.Children.Add(relationExpression2);
        }

        public RelationExpression(OperationExpression operationExpression, RelationOperator relationOperator, RelationExpression relationExpression)
            : this()
        {
            RelationExpression relationExpression1 = new RelationExpression(operationExpression);
            this.Children.Add(relationExpression1);
            
            RelationExpression relationExpression2;
            if (relationExpression.RelationOperator == RelationOperator.None)
            {
                relationExpression2 = relationExpression;
            }
            else
            {
                relationExpression2 = new RelationExpression(relationExpression);
            }
            relationExpression2.RelationOperator = relationOperator;
            this.Children.Add(relationExpression2);
        }

        public RelationExpression(RelationExpression relationExpression1, RelationOperator relationOperator, RelationExpression relationExpression2)
            : this()
        {
            this.Children.Add(relationExpression1);

            if (relationExpression2.RelationOperator != RelationOperator.None)
            {
                relationExpression2 = new RelationExpression(relationExpression2);
            }
            relationExpression2.RelationOperator = relationOperator;
            this.Children.Add(relationExpression2);
        }

        public RelationExpression(RelationExpression relationExpression, RelationOperator relationOperator, OperationExpression operationExpression)
            : this()
        {
            RelationExpression relationExpression1 = relationExpression;
            this.Children.Add(relationExpression1);
            RelationExpression relationExpression2 = new RelationExpression(operationExpression);
            relationExpression2.RelationOperator = relationOperator;
            this.Children.Add(relationExpression2);
        }

        public bool IsFormatted
        {
            get;
            set;
        }


        public RelationExpression(RelationExpression relationExpression1, RelationOperator relationOperator, RelationExpression relationExpression2, bool format)
            : this()
        {
            this.IsFormatted = format;
            if (format)
            {
                this.Children.Add(relationExpression1);
                this.RelationOperator = relationOperator;
                this.Children.Add(relationExpression2);
            }
            else
            {
                this.Children.Add(relationExpression1);

                if (relationExpression2.RelationOperator != RelationOperator.None)
                {
                    relationExpression2 = new RelationExpression(relationExpression2);
                }
                relationExpression2.RelationOperator = relationOperator;
                this.Children.Add(relationExpression2);
            }
        }
        #endregion

        public void AddExpression(RelationExpression relationExpression)
        {
            this.Children.Add(relationExpression);
        }

        public void AddExpression(OperationExpression operationExpression)
        {
            RelationExpression relationExpression = new RelationExpression(operationExpression);
            AddExpression(relationExpression);
        }

        public void AddExpression(RelationOperator relationOperator, OperationExpression operationExpression)
        {
            RelationExpression relationExpression = new RelationExpression(operationExpression);
            relationExpression.RelationOperator = relationOperator;
            AddExpression(relationExpression);
        }

        #region 与
        public void And(RelationExpression relationExpression)
        {
            if (relationExpression.RelationOperator != RelationOperator.None)
            {
                relationExpression = new RelationExpression(relationExpression);
            }
            relationExpression.RelationOperator = RelationOperator.And;
            this.Children.Add(relationExpression);
        }

        public void And(OperationExpression operationExpression)
        {
            RelationExpression relationExpression = new RelationExpression(operationExpression);
            And(relationExpression);
        }

        #endregion
        #region 或
        public void Or(RelationExpression relationExpression)
        {
            if (relationExpression.RelationOperator != RelationOperator.None)
            {
                relationExpression = new RelationExpression(relationExpression);
            }
            relationExpression.RelationOperator = RelationOperator.Or;
            this.Children.Add(relationExpression);
        }

        public void Or(OperationExpression operationExpression)
        {
            RelationExpression relationExpression = new RelationExpression(operationExpression);
            Or(relationExpression);
        }
        #endregion


        public void AddAndExpression(params RelationExpression[] relationExpressions)
        {
            foreach (RelationExpression relationExpression in relationExpressions)
            {
                relationExpression.RelationOperator = RelationOperator.And;
                this.Children.Add(relationExpression);
            }
        }

        public void AddAndExpression(params OperationExpression[] operationExpressions)
        {
            foreach (OperationExpression operationExpression in operationExpressions)
            {
                RelationExpression relationExpression = new RelationExpression(operationExpression);
                relationExpression.RelationOperator = RelationOperator.And;
                this.Children.Add(relationExpression);
            }
        }


        public void AddOrExpression(params RelationExpression[] relationExpressions)
        {
            foreach (RelationExpression relationExpression in relationExpressions)
            {
                relationExpression.RelationOperator = RelationOperator.Or;
                this.Children.Add(relationExpression);
            }
        }

        public void AddOrExpression(params OperationExpression[] operationExpressions)
        {
            foreach (OperationExpression operationExpression in operationExpressions)
            {
                RelationExpression relationExpression = new RelationExpression(operationExpression);
                relationExpression.RelationOperator = RelationOperator.Or;
                this.Children.Add(relationExpression);
            }
        }


        #region 符重载
        public static RelationExpression operator &(RelationExpression relationExpression1, RelationExpression relationExpression2)
        {
            return new RelationExpression(relationExpression1, RelationOperator.And, relationExpression1);
        }

        public static RelationExpression operator &(RelationExpression relationExpression, OperationExpression operationExpression)
        {
            return new RelationExpression(relationExpression, RelationOperator.And, operationExpression);
        }

        public static RelationExpression operator |(RelationExpression relationExpression1, RelationExpression relationExpression2)
        {
            return new RelationExpression(relationExpression1, RelationOperator.Or, relationExpression2);
        }

        public static RelationExpression operator |(RelationExpression relationExpression, OperationExpression operationExpression)
        {
            return new RelationExpression(relationExpression, RelationOperator.Or, operationExpression);
        }

        public static RelationExpression operator !(RelationExpression relationExpression)
        {
            return new RelationExpression(RelationOperator.Not, relationExpression);
        }
        #endregion
        #region 符重载
        public static ConditionExpression operator ^(RelationExpression relationExpression, SortingExpression sortingExpression)
        {
            return (new ConditionExpression(relationExpression)).OrderBy(sortingExpression);
        }

        public static ConditionExpression operator ^(RelationExpression relationExpression, ColumnExpression columnExpression)
        {
            return (new ConditionExpression(relationExpression)).OrderBy(columnExpression);
        }

        public static ConditionExpression operator ^(RelationExpression relationExpression, string columnName)
        {
            return (new ConditionExpression(relationExpression)).OrderBy(columnName);
        }
        #endregion
    }
}
